# -*- coding: utf-8 -*-

from abc import ABCMeta, abstractmethod

from .event import Event, EVENT
from .commission import ZeroCommission, PerShareCommission, PerMoneyCommission
from .slippage import ZeroSlippage, FixedPercentSlippage
from .logger import get_logger

# 执行引擎
class ExecutionHandler(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def execute_order(self, event):
        raise NotImplementedError("execute_order()")

# 模拟执行引擎, 可以模拟回测. (如果需要真实交易的花, 只需要继承基础类, 重写交易函数就行)
class SimulatedExecutionHandler(ExecutionHandler):

    def __init__(self, event_hub, bars, slippage_type='fixed', commission_type='default'):
        # bars: 数据引擎
        self.bars = bars
        # 事件引擎
        self.event_hub = event_hub
        # 手续费类型
        self.commission_type = commission_type
        # 滑点类型
        self.slippage_type = slippage_type
        self.commission = 0.0

    def _trade_with_slippage(self, event):
        # 计算经过滑点之后的价格
        order_price = self.bars.get_latest_bars(event.symbol)[0][5]

        if self.slippage_type == 'zero':
            return ZeroSlippage().get_trade_price(order_price)

        elif self.slippage_type == 'fixed':
            fixed_slippage = FixedPercentSlippage(percent=0.1)
            return fixed_slippage.get_trade_price(order_price, event.direction)

        else:
            return order_price

    def _get_commission_commission(self, event):
        # 计算该笔交易的手续费
        self.fill_price = self._trade_with_slippage(event)
        full_cost = self.fill_price * event.quantity

        if self.commission_type == 'zero':
            commission = ZeroCommission().get_commission()

        elif self.commission_type == 'default':
            if event.symbol.startswith('6'):  # 上海交易所
                if event.direction == 'BUY':  # 买入：过户费1000股1元+佣金单向万3
                    commission = PerShareCommission(rate=0.0001, min_comm=1.0).get_commission(event.quantity) + \
                                 PerMoneyCommission(rate=3.0e-4, min_comm=5.0).get_commission(full_cost)
                else:  # 卖出：印花税+过户费+佣金
                    commission = PerMoneyCommission(rate=1.0e-3).get_commission(full_cost) + \
                                 PerShareCommission(rate=0.0001, min_comm=1.0).get_commission(event.quantity) + \
                                 PerMoneyCommission(rate=3.0e-4, min_comm=5.0).get_commission(full_cost)
            elif event.symbol.startswith(('0', '3')):  # 深圳交易所
                if event.direction == 'BUY':  # 买入：佣金
                    commission = PerMoneyCommission(rate=3.0e-4, min_comm=5.0).get_commission(full_cost)
                else:  # 卖出：印花税+佣金
                    commission = PerMoneyCommission(rate=1.0e-3).get_commission(full_cost) + \
                                 PerMoneyCommission(rate=3.0e-4, min_comm=5.0).get_commission(full_cost)
            elif event.symbol.startswith('I'):  # 股指期货，按照点数计算
                commission = PerMoneyCommission(rate=3.0e-5).get_commission(full_cost)
            else:
                commission = 0.0
        else:
            commission = 0.0

        return commission

    def execute_order(self, event):
        # 执行交易. 计算手续费和滑点后成交的价格, 然后产生ACCEPT_ORDER事件(如果是限价单, 不符合交易的直接返回)
        get_logger().debug("new order event: " + event.symbol + " " + str(event.quantity) + " " + event.direction)
        self.commission = self._get_commission_commission(event)
        if event.style.get_style() == "LMT":
            if event.direction == "BUY" and event.style.get_limit_price() < self.fill_price:
                return
            if event.direction == "SELL" and event.style.get_limit_price() > self.fill_price:
                return
        timeindex = self.bars.get_latest_bars(event.symbol)[0][1]
        fill_event = Event(EVENT.ACCEPT_ORDER, timeindex=timeindex, symbol=event.symbol, quantity=event.quantity,
                           exchange='SimulatedExchange', direction=event.direction,
                           fill_price=self.fill_price, commission=self.commission)
        self.event_hub.publish_event(fill_event)





